home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / advanced97 / PAINT.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  5.6 KB  |  267 lines

  1. #include <assert.h>
  2. #include <math.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <GL/glut.h>
  6. #include "texture.h"
  7.  
  8. /* Some <math.h> files do not define M_PI... */
  9. #ifndef M_PI
  10. #define M_PI 3.14159265358979323846
  11. #endif
  12.  
  13. #ifndef __sgi
  14. #define trunc(x) ((double)((int)(x)))
  15. #endif
  16.  
  17. #define RW 0.3086
  18. #define GW 0.6094
  19. #define BW 0.0820
  20.  
  21. static char defaultFile0[] = "data/mandrill256.rgb";
  22. static char defaultFile1[] = "data/weave.bw";
  23. static char defaultBrushFile[] = "data/brush3.rgb";
  24. GLuint *img0, *img1, *brush;
  25. GLsizei w0, w1, wbrush, h0, h1, hbrush;
  26. GLsizei w, h;
  27.  
  28. GLint comp;
  29.  
  30. void init(void)
  31. {
  32.   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  33. }
  34.  
  35. GLuint *load_img(const char *fname, GLsizei *imgW, GLsizei *imgH)
  36. {
  37.   GLuint *img;
  38.  
  39.   img = read_texture(fname, imgW, imgH, &comp);
  40.   if (!img) {
  41.     fprintf(stderr, "Could not open %s\n", fname);
  42.     exit(1);
  43.   }
  44.  
  45.   return img;
  46. }
  47.  
  48. GLuint *
  49. resize_img(GLuint *img, GLsizei curW, GLsizei curH)
  50. {
  51.   /* save & set buffer settings */
  52.   glPushAttrib(GL_COLOR_BUFFER_BIT | GL_PIXEL_MODE_BIT);
  53.   glDrawBuffer(GL_BACK);
  54.   glReadBuffer(GL_BACK);
  55.  
  56.   glPixelZoom((float)w / (float)curW, (float)h / (float)curH);
  57.   glRasterPos2i(0, 0);
  58.   glDrawPixels(curW, curH, GL_RGBA, GL_UNSIGNED_BYTE, img);
  59.   free(img);
  60.   img = (GLuint *)malloc(w * h * sizeof(GLuint));
  61.   if (!img) {
  62.     fprintf(stderr, "Malloc of %d bytes failed.\n", 
  63.         curW * curH * sizeof(GLuint));
  64.     exit(1);
  65.   }
  66.   glPixelZoom(1, 1);
  67.   glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img);
  68.  
  69.   glPopAttrib();
  70.  
  71.   return img;
  72. }
  73.  
  74. GLuint *
  75. convert_to_luminance(GLuint *img, GLsizei w, GLsizei h)
  76. {
  77.   GLubyte *newImg, *src, *dst;
  78.   GLfloat val;
  79.   int i;
  80.  
  81.   newImg = (GLubyte *)malloc(w * h);
  82.   if (!newImg) {
  83.     fprintf(stderr, "malloc of %d bytes failed\n", w*h);
  84.     exit(1);
  85.   }
  86.  
  87.   src = (GLubyte *)img;
  88.   dst = newImg;
  89.   for (i = 0; i < w*h; i++) {
  90.     val = ((float)(*src++) * RW + 
  91.        (float)(*src++) * GW +
  92.        (float)(*src++) * BW);
  93.     src++;
  94.     if (val > 255) val = 255;
  95.     *dst++ = val;
  96.   }
  97.   free(img);
  98.  
  99.   /* casting a ubyte ptr to a uint pointer is sloppy since it can
  100.    * lead to alignment errors, but since the pointer came from
  101.    * malloc we know it's legal in this case... */
  102.   return (GLuint *)newImg;
  103. }
  104.  
  105. void reshape(GLsizei winW, GLsizei winH) 
  106. {
  107.     glViewport(0, 0, w, h);
  108.     glLoadIdentity();
  109.     glOrtho(0, winW, 0, winH, 0, 5);
  110. }
  111.  
  112. void draw(void)
  113. {
  114.   static int first = 1;
  115.   GLenum err;
  116.  
  117.   if (first) {
  118.     printf("Scaling images to %d by %d\n", w, h);
  119.  
  120.     if (w0 != w || h0 != h) {
  121.       img0 = resize_img(img0, w0, h0);
  122.  
  123.     }
  124.     if (w1 != w || h1 != h) {
  125.       img1 = resize_img(img1, w1, h1);
  126.     }
  127.  
  128.     first = 0;
  129.   }
  130.   
  131.   glClear(GL_COLOR_BUFFER_BIT);
  132.   glRasterPos2i(0, 0);
  133.   glDrawBuffer(GL_BACK);
  134.   glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, img1);
  135.   glDrawBuffer(GL_FRONT);
  136.   glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, img0);
  137.   
  138.   err = glGetError();
  139.   if (err != GL_NO_ERROR) printf("Error:  %s\n", gluErrorString(err));
  140. }
  141.  
  142. int lastX, lastY, curX, curY;
  143.  
  144. int get_msecs(void)
  145. {
  146.   return glutGet(GLUT_ELAPSED_TIME) / 1000.0;
  147. }
  148.  
  149. void idle(void)
  150. {
  151.   int x = curX - (wbrush/2);
  152.   int y = h - (curY + (hbrush/2));
  153.   int msecs;
  154.   static int last_msecs = -1;
  155.  
  156.   /* do not do this more than 60 times a second.  Otherwise it's
  157.    * to fast for use on high-end systems */
  158.   msecs = get_msecs();
  159.   if (fabs(last_msecs - msecs) < 1000./60.) {
  160.     return;
  161.   }
  162.   last_msecs = msecs;
  163.  
  164.   /* we draw the brush using a drawpixels command.  on systems with
  165.    * hardware-accelerated texture mapping it would be better to use
  166.    * that. 
  167.    * 
  168.    * we use the bitmap hack to set the rasterpos because we don't
  169.    * know that the position will be within the window. 
  170.    */
  171.   glRasterPos2i(0, 0);
  172.   glBitmap(0, 0, 0, 0, x, y, 0);
  173.   glColorMask(0, 0, 0, 1);
  174.   glDrawBuffer(GL_BACK);
  175.   glDrawPixels(wbrush, hbrush, GL_ALPHA, GL_UNSIGNED_BYTE, brush);
  176.   glColorMask(1, 1, 1, 1);
  177.   
  178.   glReadBuffer(GL_BACK);
  179.   glDrawBuffer(GL_FRONT);
  180.   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  181.   glEnable(GL_BLEND);
  182.   glCopyPixels(x, y, wbrush, hbrush, GL_COLOR);
  183.   glDisable(GL_BLEND);
  184.   
  185.   glColorMask(1, 1, 1, 1);
  186. }
  187.  
  188. void motion(int xpos, int ypos)
  189. {
  190.   curX = xpos;
  191.   curY = ypos;
  192. }
  193.  
  194. /* ARGSUSED */
  195. void button(int button, int state, int xpos, int ypos)
  196. {
  197.   if (state == GLUT_DOWN) {
  198.     glutIdleFunc(idle); 
  199.     lastX = lastY = -1;
  200.     curX = xpos;
  201.     curY = ypos;
  202.     return;
  203.   } else {
  204.     glutIdleFunc(0);
  205.   }
  206. }
  207.  
  208. /* ARGSUSED1 */
  209. void key(unsigned char key, int x, int y)
  210. {
  211.   if (key == 27) exit(0);
  212. }
  213.  
  214. void 
  215. show_usage(void)
  216. {
  217.   fprintf(stderr, "Usage:\n");
  218.   fprintf(stderr, "paint [imagefile0] [imagefile1] [brush]\n");
  219. }
  220.  
  221. main(int argc, char *argv[])
  222. {
  223.   const char *fileName0 = defaultFile0, *fileName1 = defaultFile1,
  224.   *brushName = defaultBrushFile;
  225.   
  226.   glutInit(&argc, argv);
  227.   if (argc > 1) {
  228.     fileName0 = argv[1];
  229.   } 
  230.   if (argc > 2) {
  231.     fileName1 = argv[2];
  232.   } 
  233.   if (argc > 3) {
  234.     brushName = argv[3];
  235.   } 
  236.   if (argc > 4) {
  237.     show_usage();
  238.     exit(1);
  239.   }
  240.   printf("Image file 1 is %s\n", fileName0);
  241.   printf("Image file 2 is %s\n", fileName1);
  242.   printf("Brush file is %s\n", brushName);
  243.  
  244.   img0 = load_img(fileName0, &w0, &h0);
  245.   img1 = load_img(fileName1, &w1, &h1);
  246.   brush = load_img(brushName, &wbrush, &hbrush);
  247.   brush = convert_to_luminance(brush, wbrush, hbrush);
  248.  
  249. #define MAX(a, b) ((a) > (b) ? (a) : (b))
  250.   w = MAX(w0, w1);
  251.   h = MAX(h0, h1);
  252.  
  253.   glutInitWindowSize(w, h);
  254.   glutInitWindowPosition(0, 0);
  255.   glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA);
  256.   glutCreateWindow(argv[0]);
  257.   glutDisplayFunc(draw);
  258.   glutKeyboardFunc(key);
  259.   glutReshapeFunc(reshape);
  260.   glutMouseFunc(button);
  261.   glutMotionFunc(motion);
  262.   init();
  263.  
  264.   glutMainLoop();
  265.   return 0;
  266. }
  267.